/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package fr.ove.openmath.courses;

/**
 *
 * @author Mr.Sam
 */
import java.applet.Applet;
import java.awt.*;
import java.util.*;
import java.io.*;
import fr.ove.applet.*;
import fr.ove.applet.events.*;
import fr.ove.utils.Connection;
import fr.ove.openmath.OpenMathizable;
import fr.ove.openmath.compounder.OMCompounder;
import fr.ove.openmath.courses.*;
import fr.ove.openmath.jome.Jome;
import fr.ove.openmath.mathematica.ResponseReader;

/**
*
*/
public class CompounderApplet extends Applet implements AppletListener, OpenMathizable {
    /**
    * The connection used if we first have to send the result of the composition
    * to a CAS before rendering.
    */
    private Connection connection;
    
    /**
    * Flag to indicates if we first have to send the result of the composition
    * to a CAS before rendering.<BR>
    * The default behaviour is only displaying the result of the composition.
    */
    private boolean doCalculation = false;
    
    /**
    * The reader of the response sent back by the CAS.
    */
    private ResponseReader reader;
    
    /**
    * The compounder.
    */
    private OMCompounder compounder;
    
    /**
    * The list of elements of the composition and their value.
    */
    private CheckedRegistry registry;
    
    /**
    * JOME for the rendering of the formula
    */
    private Jome jome;
    
    /**
    * Initializes the instance.
    */
    public void init() {
		setLayout(new BorderLayout(0,0));
		setBackground(Color.white);
		
		jome = new Jome();
		jome.setShiftX(10);
		jome.setDrawBounds(false);
		jome.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
		jome.setFont(new Font("Times New Roman", Font.PLAIN, 14));
		add("Center", jome);
        
        String description = getParameter("description");
        if (description != null) {
            try {
                InputStream is = getClass().getResourceAsStream(description);
                BufferedReader br = new BufferedReader(new InputStreamReader(is));
                String line;
                StringBuffer buffer = new StringBuffer();
                while ((line = br.readLine()) != null) {
                    buffer.append(line);
                }
                description = buffer.toString();
                
                System.out.println("Description :");
                System.out.println(description);
                
                compounder = new OMCompounder();
                compounder.setSource(description);
            }
            catch (IOException ioe) {
                System.out.println("Failed to find the description");
                ioe.printStackTrace();
            }
        }
        
        // We got the description, get the elements for the compostions
        String elements = getParameter("listened");
        if (elements != null) {
            StringTokenizer tokenizer = new StringTokenizer(elements, "{, }");
            registry = new CheckedRegistry();
            int numArg = 1;
            String arg;
            while (tokenizer.hasMoreTokens()) {
                arg = "arg" + numArg++;
                 registry.add((String) tokenizer.nextElement(), null, arg);
             }

        }
        
        String strDoCalculation = getParameter("doCalculation");
        if ((strDoCalculation != null) && strDoCalculation.equals("true")) {
            doCalculation = true;
            // Need to calculate ==> get the port number to connect to the server.
            String strPortNumber = getParameter("portNumber");
            try {
                int portNumber = Integer.parseInt(strPortNumber);
                connection = new Connection(getDocumentBase().getHost(), portNumber);
                try {
                    
                    System.out.println("Ouverture de la conn");
                    
                    connection.open();
                }
                catch (IOException ioe) {
                    doCalculation = false;
                    System.out.println("Failed to open a connection");
                    ioe.printStackTrace();
                }
                catch (Exception e) {
                    // Thanks to IE (others too ???), if opening a connection failed then something else
                    // than a IOException is throw (a com.ms...... exception instead).
                    // That's the reason why of this catch clause :o(
                    doCalculation = false;
                    System.out.println("Failed to open a connection");
                    e.printStackTrace();
                }
            }
            catch (NumberFormatException nfe) {
                System.out.println("Invalid port number specification");
                nfe.printStackTrace();
            }
            
            if (connection.isOpened())
                reader = new ResponseReader(); // Creation of the response reader
        }
    }
    
    /**
    * Consumes (i.e. treats) the event received.
    * @param appletEvent the event to consume.
    */
    public void consumeAppletEvent(AppletEvent appletEvent) {
        ListenableApplet listenableApplet = (ListenableApplet) appletEvent.getSource();
        String appletName = listenableApplet.getName();
        
        Object action = appletEvent.getAction();
        Object argument = appletEvent.getArgument();
        
        // if the following test is true, this means the listened applet has finished loading.
        // We keep track of it in the registry which is only used to determine if all the listened
        // have been loaded. We add the listened applet inside the compounder.
        if ((action == null) && (argument == null)) {
            if (listenableApplet instanceof AppletLoadingChecked) {
                OpenMathizable omizable = (OpenMathizable) ((AppletLoadingChecked) listenableApplet).getTheApplet();
                registry.setOMizable(appletName, omizable);
                compounder.addElement(registry.getArg(appletName), omizable);
            }
        }
        
        if (registry.gotAll()) {
            compounder.compound();
            String compounded = compounder.getCompounded();
            if (doCalculation) {
                try {
                    
                    System.out.println("Ecriture dans la conn");
                    
                    connection.getOutputStream().write(compounded.getBytes());
                    String response = reader.read(connection.getInputStream());
                    // if we got it, send it to the server
                    if (response != null)
                        setOpenMath(response);
                    else
                        setOpenMath(compounded);
                }
                catch (IOException ioe) {
                    System.out.println("Communication problems encountered");
                    ioe.printStackTrace();
                }
            }
            else
                setOpenMath(compounded);
        }
        
        if (getParent() instanceof ListenableApplet) {
            ListenableApplet parentApplet = (ListenableApplet) getParent();
            
    	    AppletEvent thisAppletEvent = new AppletEvent(parentApplet);
    	    thisAppletEvent.setAction(parentApplet.getName(), this);
    	    parentApplet.fireAppletEvent(thisAppletEvent);
    	}
    }
    
    /**
    * Sets the OpenMath object.
    * @param obj the OpenMath object.
    */
    public void setOpenMath(String openMath) {
        jome.setOpenMath(openMath);
    }
    
    /**
    * Returns the OpenMath object.
    */
    public String getOpenMath() {
        return jome.getOpenMath();
    }
}